package com.gitee.qdbp.jdbc.biz;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.gitee.qdbp.able.convert.MapToBeanConverter;
import com.gitee.qdbp.able.exception.ServiceException;
import com.gitee.qdbp.able.jdbc.condition.DbUpdate;
import com.gitee.qdbp.able.jdbc.condition.DbWhere;
import com.gitee.qdbp.able.jdbc.fields.Fields;
import com.gitee.qdbp.able.jdbc.fields.IncludeFields;
import com.gitee.qdbp.able.jdbc.model.PkEntity;
import com.gitee.qdbp.able.jdbc.ordering.Orderings;
import com.gitee.qdbp.able.result.ResultCode;
import com.gitee.qdbp.jdbc.api.CrudDao;
import com.gitee.qdbp.jdbc.api.SqlBoot;
import com.gitee.qdbp.jdbc.api.SqlBufferJdbcOperations;
import com.gitee.qdbp.jdbc.api.SqlDao;
import com.gitee.qdbp.jdbc.api.SqlOperator;
import com.gitee.qdbp.jdbc.exception.DbErrorCode;
import com.gitee.qdbp.jdbc.model.AllFieldColumn;
import com.gitee.qdbp.jdbc.model.DbVersion;
import com.gitee.qdbp.jdbc.model.FieldScene;
import com.gitee.qdbp.jdbc.model.SimpleFieldColumn;
import com.gitee.qdbp.jdbc.model.ValidStrategy;
import com.gitee.qdbp.jdbc.plugins.BatchInsertExecutor;
import com.gitee.qdbp.jdbc.plugins.BatchUpdateExecutor;
import com.gitee.qdbp.jdbc.plugins.DbConditionConverter;
import com.gitee.qdbp.jdbc.plugins.DbPluginHelper;
import com.gitee.qdbp.jdbc.plugins.EntityDataStateFillStrategy;
import com.gitee.qdbp.jdbc.plugins.EntityFieldFillExecutor;
import com.gitee.qdbp.jdbc.plugins.EntityFieldFillStrategy;
import com.gitee.qdbp.jdbc.plugins.SqlDialect;
import com.gitee.qdbp.jdbc.sql.SqlBuffer;
import com.gitee.qdbp.jdbc.sql.SqlBuilder;
import com.gitee.qdbp.jdbc.sql.SqlTools;
import com.gitee.qdbp.jdbc.sql.build.CommonSqlTools;
import com.gitee.qdbp.jdbc.sql.build.CrudSqlHelper;
import com.gitee.qdbp.jdbc.sql.fragment.CrudFragmentHelper;
import com.gitee.qdbp.jdbc.sql.parse.SqlFragmentContainer;
import com.gitee.qdbp.jdbc.utils.ParseTools;
import com.gitee.qdbp.tools.utils.ConvertTools;
import com.gitee.qdbp.tools.utils.MapTools;
import com.gitee.qdbp.tools.utils.VerifyTools;

/**
 * 基础增删改查数据库操作
 *
 * @author 赵卉华
 * @version 190601
 */
public class CrudDaoImpl<T> extends BaseQueryerImpl<T> implements CrudDao<T> {

    private static final Logger log = LoggerFactory.getLogger(CrudDaoImpl.class);
    protected final Class<T> beanClass;
    protected final SqlBoot sqlBoot;
    protected final SqlDao sqlDao;
    protected final CrudSqlOperator sqlOperator;
    /** 批量执行时的大小限制(0为无限制) **/
    protected int defaultBatchSize = QdbcBootImpl.DEFAULT_BATCH_SIZE;

    CrudDaoImpl(Class<T> c, SqlBoot sqlBoot, SqlDao sqlDao, SqlBufferJdbcOperations jdbc) {
        super(new CrudSqlHelper(c, sqlBoot), newEntityFieldFillExecutor(c, sqlBoot), jdbc,
                sqlBoot.plugins().getRowToBeanMapper(c));
        this.beanClass = c;
        this.sqlBoot = sqlBoot;
        this.sqlDao = sqlDao;
        this.sqlOperator = new CrudSqlOperator(c, sqlBoot);
    }

    private static EntityFieldFillExecutor newEntityFieldFillExecutor(Class<?> clazz, SqlBoot sqlBoot) {
        DbPluginHelper plugins = sqlBoot.plugins();
        AllFieldColumn<?> allFields = plugins.parseAllFieldColumns(clazz);
        EntityFieldFillStrategy fieldFillStrategy = plugins.getEntityFieldFillStrategy();
        EntityDataStateFillStrategy<?> dataStateFillStrategy = plugins.getEntityDataStateFillStrategy();
        return new EntityFieldFillExecutor(allFields, fieldFillStrategy, dataStateFillStrategy);
    }

    @Override
    public CrudSqlHelper sqlHelper() {
        return (CrudSqlHelper) this.sqlHelper;
    }

    @Override
    public T findById(Serializable id) {
        return findById(Fields.ALL, id);
    }

    @Override
    public T findById(Fields fields, Serializable id) {
        VerifyTools.requireNotBlank(id, "id");
        SimpleFieldColumn pk = sqlHelper().fragment().getPrimaryKey();
        if (pk == null) { // 没有找到主键字段
            String details = "UnsupportedFindById, class=" + beanClass.getName();
            throw new ServiceException(DbErrorCode.DB_PRIMARY_KEY_FIELD_IS_UNRESOLVED, details);
        }
        String primaryField = pk.getFieldName();
        DbWhere where = new DbWhere().on(primaryField).equals(id).end();
        return this.find(fields, where);
    }

    @Override
    public List<T> listByIds(Collection<? extends Serializable> ids, Orderings orderings) throws ServiceException {
        VerifyTools.requireNotBlank(ids, "ids");
        return listByIds(Fields.ALL, ids, orderings);
    }

    @Override
    public List<T> listByIds(Fields fields, Collection<? extends Serializable> ids, Orderings orderings)
            throws ServiceException {
        SimpleFieldColumn pk = sqlHelper().fragment().getPrimaryKey();
        if (pk == null) { // 没有找到主键字段
            String details = "UnsupportedListByIds, class=" + beanClass.getName();
            throw new ServiceException(DbErrorCode.DB_PRIMARY_KEY_FIELD_IS_UNRESOLVED, details);
        }
        String primaryField = pk.getFieldName();
        DbWhere where = new DbWhere().on(primaryField).in(ids).end();
        return list(fields, where, orderings);
    }

    @Override
    public List<T> listChildren(String startCode, String codeField, String parentField, DbWhere filterWhere,
            DbWhere searchWhere, Orderings orderings) {
        VerifyTools.requireNotBlank(startCode, "startCode");
        VerifyTools.requireNotBlank(codeField, "codeField");
        VerifyTools.requireNotBlank(parentField, "parentField");

        List<String> startCodes = Collections.singletonList(startCode);
        return doListChildren(startCodes, codeField, parentField, filterWhere, searchWhere, orderings);
    }

    @Override
    public List<T> listChildren(List<String> startCodes, String codeField, String parentField, DbWhere filterWhere,
            DbWhere searchWhere, Orderings orderings) {
        VerifyTools.requireNotBlank(startCodes, "startCodes");
        VerifyTools.requireNotBlank(codeField, "codeField");
        VerifyTools.requireNotBlank(parentField, "parentField");

        return doListChildren(startCodes, codeField, parentField, filterWhere, searchWhere, orderings);
    }

    private List<T> doListChildren(List<String> startCodes, String codeField, String parentField, DbWhere filterWhere,
            DbWhere searchWhere, Orderings orderings) {
        DbWhere filter = checkWhere(filterWhere);
        DbWhere search = checkWhere(searchWhere);
        // 数据状态填充在filterWhere中
        entityFieldFillExecutor.fillQueryWhereDataState(filter, getMajorTableAlias());
        // 数据权限填充在searchWhere中
        entityFieldFillExecutor.fillQueryWhereParams(search, getMajorTableAlias());

        return doListChildren(startCodes, codeField, parentField, Fields.ALL, filter, search, orderings, beanClass);
    }

    @Override
    public List<String> listChildrenCodes(String startCode, String codeField, String parentField, DbWhere filterWhere,
            DbWhere searchWhere, Orderings orderings) {
        VerifyTools.requireNotBlank(startCode, "startCode");
        VerifyTools.requireNotBlank(codeField, "codeField");
        VerifyTools.requireNotBlank(parentField, "parentField");

        List<String> startCodes = Collections.singletonList(startCode);
        return doListChildrenCodes(startCodes, codeField, parentField, filterWhere, searchWhere, orderings);
    }

    @Override
    public List<String> listChildrenCodes(List<String> startCodes, String codeField, String parentField,
            DbWhere filterWhere, DbWhere searchWhere, Orderings orderings) {
        VerifyTools.requireNotBlank(startCodes, "startCodes");
        VerifyTools.requireNotBlank(codeField, "codeField");
        VerifyTools.requireNotBlank(parentField, "parentField");

        return doListChildrenCodes(startCodes, codeField, parentField, filterWhere, searchWhere, orderings);
    }

    private List<String> doListChildrenCodes(List<String> startCodes, String codeField, String parentField,
            DbWhere filterWhere, DbWhere searchWhere, Orderings orderings) {
        DbWhere filter = checkWhere(filterWhere);
        DbWhere search = checkWhere(searchWhere);
        // 数据状态填充在filterWhere中
        entityFieldFillExecutor.fillQueryWhereDataState(filter, getMajorTableAlias());
        // 数据权限填充在searchWhere中
        entityFieldFillExecutor.fillQueryWhereParams(search, getMajorTableAlias());

        IncludeFields fields = new IncludeFields(codeField);
        return doListChildren(startCodes, codeField, parentField, fields, filter, search, orderings, String.class);
    }

    @Override
    public List<T> listParents(String startCode, String codeField, String parentField, DbWhere filterWhere,
            DbWhere searchWhere, Orderings orderings) {
        VerifyTools.requireNotBlank(startCode, "startCode");
        VerifyTools.requireNotBlank(codeField, "codeField");
        VerifyTools.requireNotBlank(parentField, "parentField");

        List<String> startCodes = Collections.singletonList(startCode);
        return doListParents(startCodes, codeField, parentField, filterWhere, searchWhere, orderings);
    }

    @Override
    public List<T> listParents(List<String> startCodes, String codeField, String parentField, DbWhere filterWhere,
            DbWhere searchWhere, Orderings orderings) {
        VerifyTools.requireNotBlank(startCodes, "startCodes");
        VerifyTools.requireNotBlank(codeField, "codeField");
        VerifyTools.requireNotBlank(parentField, "parentField");

        return doListParents(startCodes, codeField, parentField, filterWhere, searchWhere, orderings);
    }

    private List<T> doListParents(List<String> startCodes, String codeField, String parentField, DbWhere filterWhere,
            DbWhere searchWhere, Orderings orderings) {
        DbWhere filter = checkWhere(filterWhere);
        DbWhere search = checkWhere(searchWhere);
        // 数据状态填充在filterWhere中
        entityFieldFillExecutor.fillQueryWhereDataState(filter, getMajorTableAlias());
        // 数据权限填充在searchWhere中
        entityFieldFillExecutor.fillQueryWhereParams(search, getMajorTableAlias());

        if (orderings != null && !orderings.isEmpty()) {
            return doListParents(startCodes, codeField, parentField, Fields.ALL, filter, search, orderings, beanClass);
        } else {
            // 如果startCode只有一个, 且未指定排序字段, 则结果会保证顺序从顶级节点开始依次排列
            Map<String, Object> params = generateRecursiveParams(startCodes, codeField, parentField, Fields.ALL,
                    filterWhere, searchWhere, orderings);

            String sqlId = "GlobalRecursive:recursiveListParentsQuery";
            List<Map<String, Object>> list = sqlDao.listForMaps(sqlId, params);

            List<Map<String, Object>> sorted = MapTools.sortTreeNodes(list, codeField, parentField);

            List<T> results = new ArrayList<>();
            MapToBeanConverter converter = sqlBoot.plugins().getMapToBeanConverter();
            for (Map<String, Object> item : sorted) {
                T entity = converter.convert(item, beanClass);
                results.add(entity);
            }
            return results;
        }
    }

    @Override
    public List<String> listParentCodes(String startCode, String codeField, String parentField, DbWhere filterWhere,
            DbWhere searchWhere, Orderings orderings) {
        VerifyTools.requireNotBlank(startCode, "startCode");
        VerifyTools.requireNotBlank(codeField, "codeField");
        VerifyTools.requireNotBlank(parentField, "parentField");

        List<String> startCodes = Collections.singletonList(startCode);
        return doListParentCodes(startCodes, codeField, parentField, filterWhere, searchWhere, orderings);
    }

    @Override
    public List<String> listParentCodes(List<String> startCodes, String codeField, String parentField,
            DbWhere filterWhere, DbWhere searchWhere, Orderings orderings) {
        VerifyTools.requireNotBlank(startCodes, "startCodes");
        VerifyTools.requireNotBlank(codeField, "codeField");
        VerifyTools.requireNotBlank(parentField, "parentField");

        return doListParentCodes(startCodes, codeField, parentField, filterWhere, searchWhere, orderings);
    }

    private List<String> doListParentCodes(List<String> startCodes, String codeField, String parentField,
            DbWhere filterWhere,
            DbWhere searchWhere, Orderings orderings) {
        DbWhere filter = checkWhere(filterWhere);
        DbWhere search = checkWhere(searchWhere);
        // 数据状态填充在filterWhere中
        entityFieldFillExecutor.fillQueryWhereDataState(filter, getMajorTableAlias());
        // 数据权限填充在searchWhere中
        entityFieldFillExecutor.fillQueryWhereParams(search, getMajorTableAlias());

        if (orderings != null && !orderings.isEmpty()) {
            IncludeFields fields = new IncludeFields(codeField);
            return doListParents(startCodes, codeField, parentField, fields, filter, search, orderings,
                    String.class);
        } else {
            IncludeFields fields = new IncludeFields(codeField, parentField);
            Map<String, Object> params = generateRecursiveParams(startCodes, codeField, parentField, fields,
                    filterWhere, searchWhere, orderings);

            String sqlId = "GlobalRecursive:recursiveListParentsQuery";
            List<Map<String, Object>> list = sqlDao.listForMaps(sqlId, params);

            List<Map<String, Object>> sorted = MapTools.sortTreeNodes(list, codeField, parentField);
            List<String> results = new ArrayList<>();
            for (Map<String, Object> item : sorted) {
                Object codeValue = item.get(codeField);
                if (codeValue != null) {
                    results.add(codeValue.toString());
                }
            }
            return results;
        }
    }

    // ORACLE： START WITH {codeField} IN( {startCode} ) CONNECT BY PRIOR {codeField}={parentField}
    // DB2: 使用WITH递归 
    // MYSQL 8.0+: 使用WITH RECURSIVE递归 
    // MYSQL 8.0-: 使用存储过程RECURSIVE_LIST_CHILDREN_QUERY
    protected <R> List<R> doListChildren(List<String> startCodes, String codeField, String parentField, Fields fields,
            DbWhere filter, DbWhere search, Orderings orderings, Class<R> resultType) throws ServiceException {
        return doListRecursive("Children", startCodes, codeField, parentField, fields, filter, search, orderings,
                resultType);
    }

    protected <R> List<R> doListParents(List<String> startCodes, String codeField, String parentField, Fields fields,
            DbWhere filter, DbWhere search, Orderings orderings, Class<R> resultType) throws ServiceException {
        return doListRecursive("Parents", startCodes, codeField, parentField, fields, filter, search, orderings,
                resultType);
    }

    protected <R> List<R> doListRecursive(String type, List<String> startCodes, String codeField, String parentField,
            Fields selectFields, DbWhere filterWhere, DbWhere searchWhere, Orderings orderings, Class<R> resultType)
            throws ServiceException {
        Map<String, Object> params = generateRecursiveParams(startCodes, codeField, parentField, selectFields,
                filterWhere, searchWhere, orderings);

        String sqlId = "GlobalRecursive:recursiveList" + type + "Query";
        return sqlDao.listForObjects(sqlId, params, resultType);
    }

    private Map<String, Object> generateRecursiveParams(List<String> startCodes, String codeField, String parentField,
            Fields selectFields, DbWhere filterWhere, DbWhere searchWhere, Orderings orderings) {
        CrudFragmentHelper sqlHelper = sqlHelper().fragment();
        String codeColumn = sqlHelper.getColumnName(FieldScene.CONDITION, codeField);
        String parentColumn = sqlHelper.getColumnName(FieldScene.CONDITION, parentField);
        SqlBuffer selectColumns = sqlHelper.buildSelectFieldsSql(selectFields);

        Map<String, Object> params = new HashMap<>();
        params.put("codeColumn", codeColumn);
        params.put("parentColumn", parentColumn);
        params.put("tableName", sqlHelper.getTableName());
        params.put("selectColumns", selectColumns);
        params.put("startCodes", startCodes);
        if (filterWhere != null && !filterWhere.isEmpty()) {
            params.put("filterWhere", sqlHelper.buildWhereSql(filterWhere, false));
        }
        if (searchWhere != null && !searchWhere.isEmpty()) {
            params.put("searchWhere", sqlHelper.buildWhereSql(searchWhere, false));
        }
        if (orderings != null && !orderings.isEmpty()) {
            params.put("orderBy", sqlHelper.buildOrderBySql(orderings, false));
        }
        return params;
    }

    protected Map<String, Object> copmareMapDifference(Map<String, Object> original, Map<String, Object> current) {
        Map<String, Object> diff = new HashMap<>();
        for (Map.Entry<String, Object> entry : original.entrySet()) {
            if (!current.containsKey(entry.getKey())) {
                diff.put(entry.getKey(), null);
            }
        }
        for (Map.Entry<String, Object> entry : current.entrySet()) {
            Object curvalue = SqlTools.unwrapDbVariable(entry.getValue());
            Object orivalue = SqlTools.unwrapDbVariable(original.get(entry.getKey()));
            if (VerifyTools.notEquals(curvalue, orivalue)) {
                diff.put(entry.getKey(), curvalue);
            }
        }
        return diff;
    }

    @Override
    public String insert(T entity) throws ServiceException {
        VerifyTools.requireNonNull(entity, "entity");
        return executeInsert(entity, ValidStrategy.AUTO, true);
    }

    @Override
    public String insert(T entity, boolean fillCreateParams) throws ServiceException {
        VerifyTools.requireNonNull(entity, "entity");
        return executeInsert(entity, ValidStrategy.AUTO, fillCreateParams);
    }

    @Override
    public String insert(Map<String, Object> entity) throws ServiceException {
        VerifyTools.requireNonNull(entity, "entity");
        return executeInsert(entity, ValidStrategy.AUTO, true);
    }

    @Override
    public String insert(Map<String, Object> entity, boolean fillCreateParams) throws ServiceException {
        VerifyTools.requireNonNull(entity, "entity");
        return executeInsert(entity, ValidStrategy.AUTO, fillCreateParams);
    }

    @Override
    public String insert(T entity, ValidStrategy validStrategy) throws ServiceException {
        VerifyTools.requireNonNull(entity, "entity");
        return executeInsert(entity, validStrategy, true);
    }

    @Override
    public String insert(T entity, ValidStrategy validStrategy, boolean fillCreateParams) throws ServiceException {
        VerifyTools.requireNonNull(entity, "entity");
        return executeInsert(entity, validStrategy, fillCreateParams);
    }

    @Override
    public String insert(Map<String, Object> entity, ValidStrategy validStrategy) throws ServiceException {
        VerifyTools.requireNonNull(entity, "entity");
        return executeInsert(entity, validStrategy, true);
    }

    @Override
    public String insert(Map<String, Object> entity, ValidStrategy validStrategy, boolean fillCreateParams)
            throws ServiceException {
        VerifyTools.requireNonNull(entity, "entity");
        return executeInsert(entity, validStrategy, fillCreateParams);
    }

    protected String executeInsert(Object object, ValidStrategy validStrategy, boolean fillCreateParams)
            throws ServiceException {
        // 将实体类转换为map, 并执行实体业务数据填充
        PkEntity pe = convertAndFillCreateParams(object, fillCreateParams);
        String id = pe.getPrimaryKey();
        Map<String, Object> readyEntity = pe.getEntity();
        // 执行数据库插入
        SqlBuffer buffer = sqlHelper().buildInsertSql(readyEntity, validStrategy);
        jdbc.insert(buffer);
        return id;
    }

    @Override
    public List<String> inserts(List<?> entities) throws ServiceException {
        return doInserts(entities, ValidStrategy.AUTO, true, this.defaultBatchSize);
    }

    @Override
    public List<String> inserts(List<?> entities, boolean fillCreateParams) throws ServiceException {
        return doInserts(entities, ValidStrategy.AUTO, fillCreateParams, this.defaultBatchSize);
    }

    @Override
    public List<String> inserts(List<?> entities, ValidStrategy validStrategy) throws ServiceException {
        return doInserts(entities, validStrategy, true, this.defaultBatchSize);
    }

    @Override
    public List<String> inserts(List<?> entities, ValidStrategy validStrategy, boolean fillCreateParams)
            throws ServiceException {
        return doInserts(entities, validStrategy, fillCreateParams, this.defaultBatchSize);
    }

    protected List<String> doInserts(List<?> entities, ValidStrategy validStrategy, boolean fillCreateParams,
            int batchSize) throws ServiceException {
        VerifyTools.requireNotBlank(entities, "entities");
        if (entities.size() == 1) {
            Object first = entities.get(0);
            String id = executeInsert(first, validStrategy, fillCreateParams);
            return ConvertTools.toList(id);
        } else if (batchSize <= 0 || entities.size() <= batchSize) {
            return doBatchInserts(entities, validStrategy, fillCreateParams);
        } else { // 分批导入
            List<String> ids = new ArrayList<>();
            List<Object> buffer = new ArrayList<>();
            for (int i = 1, size = entities.size(); i <= size; i++) {
                buffer.add(entities.get(i - 1));
                if (i % batchSize == 0 || i == size) {
                    List<String> batchIds = doBatchInserts(buffer, validStrategy, fillCreateParams);
                    ids.addAll(batchIds);
                    buffer.clear();
                }
            }
            return ids;
        }
    }

    protected List<String> doBatchInserts(List<?> entities, ValidStrategy validStrategy, boolean fillCreateParams)
            throws ServiceException {
        List<PkEntity> contents = new ArrayList<>();
        for (Object item : entities) {
            // 将实体类转换为map, 并执行实体业务数据填充
            PkEntity pe = convertAndFillCreateParams(item, fillCreateParams);
            contents.add(pe);
        }

        DbVersion version = jdbc.dbVersion();
        BatchInsertExecutor batchOperator = jdbc.plugins().getBatchInsertExecutor(version);
        // 执行批量数据库插入
        return batchOperator.inserts(contents, validStrategy, jdbc, sqlOperator);
    }

    @Override
    public int update(T entity) throws ServiceException {
        return this.update(entity, ValidStrategy.AUTO, true, false);
    }

    @Override
    public int update(T entity, boolean fillUpdateParams, boolean errorOnUnaffected) throws ServiceException {
        return this.update(entity, ValidStrategy.AUTO, fillUpdateParams, fillUpdateParams);
    }

    @Override
    public int update(T entity, ValidStrategy validStrategy) throws ServiceException {
        return this.update(entity, validStrategy, true, false);
    }

    @Override
    public int update(T entity, ValidStrategy validStrategy, boolean fillUpdateParams, boolean errorOnUnaffected)
            throws ServiceException {
        if (entity == null) {
            log.debug("Update set fields is empty, the update operation will be skipped.");
            return 0;
        }
        // 查找主键
        SimpleFieldColumn pk = sqlHelper().fragment().getPrimaryKey();
        if (pk == null) { // 没有找到主键字段
            String details = "UnsupportedUpdateById, class=" + beanClass.getName();
            throw new ServiceException(DbErrorCode.DB_PRIMARY_KEY_FIELD_IS_UNRESOLVED, details);
        }
        PkEntity pe = convertAndFillUpdateParams(entity, fillUpdateParams);
        Serializable pkValue = pe.getPrimaryKey();
        if (VerifyTools.isBlank(pkValue)) { // 主键值为空
            String details = "CanNotExecuteUpdateById, class=" + beanClass.getName();
            throw new ServiceException(DbErrorCode.DB_PRIMARY_KEY_VALUE_IS_REQUIRED, details);
        }
        // 实体类转换为DbUpdate
        DbConditionConverter converter = jdbc.plugins().getDbConditionConverter();
        DbUpdate ud = converter.parseMapToDbUpdate(pe.getEntity());
        // 生成主键限制条件
        DbWhere where = new DbWhere().on(pk.getFieldName()).equals(pkValue).end();
        entityFieldFillExecutor.fillUpdateWhereDataState(where);
        entityFieldFillExecutor.fillUpdateWhereParams(where);
        return this.doUpdate(ud, where, validStrategy, errorOnUnaffected);
    }

    @Override
    public int update(Map<String, Object> entity) throws ServiceException {
        return this.update(entity, ValidStrategy.AUTO, true, false);
    }

    @Override
    public int update(Map<String, Object> entity, boolean fillUpdateParams, boolean errorOnUnaffected)
            throws ServiceException {
        return this.update(entity, ValidStrategy.AUTO, fillUpdateParams, errorOnUnaffected);
    }

    @Override
    public int update(Map<String, Object> entity, ValidStrategy validStrategy) throws ServiceException {
        return this.update(entity, validStrategy, true, false);
    }

    @Override
    public int update(Map<String, Object> entity, ValidStrategy validStrategy, boolean fillUpdateParams,
            boolean errorOnUnaffected) throws ServiceException {
        if (entity == null || entity.isEmpty()) {
            log.debug("Update set fields is empty, the update operation will be skipped.");
            return 0;
        }
        DbConditionConverter converter = jdbc.plugins().getDbConditionConverter();
        if (!entity.containsKey("where")) { // 没有where条件, 必须要有主键
            if (entity.isEmpty()) {
                String details = "NoFieldsThatBeUpdatedWereFound, class=" + beanClass.getName();
                throw new ServiceException(DbErrorCode.DB_ENTITY_MUST_NOT_BE_EMPTY, details);
            }
            // 查找主键
            SimpleFieldColumn pk = sqlHelper().fragment().getPrimaryKey();
            if (pk == null) { // 没有找到主键字段
                String details = "UnsupportedUpdateById, class=" + beanClass.getName();
                throw new ServiceException(DbErrorCode.DB_PRIMARY_KEY_FIELD_IS_UNRESOLVED, details);
            }
            Object value = entity.get(pk.getFieldName());
            if (VerifyTools.isBlank(value)) { // 主键值为空
                String details = "CanNotExecuteUpdateById, class=" + beanClass.getName();
                throw new ServiceException(DbErrorCode.DB_PRIMARY_KEY_VALUE_IS_REQUIRED, details);
            }
            Serializable pkValue;
            if (value instanceof Serializable) {
                pkValue = (Serializable) value;
            } else {
                pkValue = value.toString();
            }
            // 填充实体的修改参数(如修改人修改时间等)
            fillEntityUpdateParams(entity, fillUpdateParams);
            // 转换为DbUpdate对象
            DbUpdate ud = converter.parseMapToDbUpdate(entity);
            // 生成主键查询条件
            DbWhere where = new DbWhere().on(pk.getFieldName()).equals(pkValue).end();
            // 填充Where条件
            entityFieldFillExecutor.fillUpdateWhereDataState(where);
            entityFieldFillExecutor.fillUpdateWhereParams(where);
            return this.doUpdate(ud, where, validStrategy, errorOnUnaffected);
        } else { // 如果Update对象中带有where字段, 将where字段值转换为DbWhere对象
            Object whereValue = entity.remove("where");
            DbWhere where;
            if (whereValue == null) {
                where = null;
            } else if (whereValue instanceof DbWhere) {
                where = (DbWhere) whereValue;
            } else if (whereValue instanceof Map) {
                @SuppressWarnings("unchecked")
                Map<String, Object> mapValue = (Map<String, Object>) whereValue;
                where = converter.parseMapToDbWhere(mapValue);
            } else if (beanClass.isAssignableFrom(whereValue.getClass())) {
                @SuppressWarnings("unchecked")
                T entityValue = (T) whereValue;
                where = converter.convertBeanToDbWhere(entityValue);
            } else {
                // whereValue只支持DbWhere/map/T
                String details = "CanNotExecuteUpdate, class=" + beanClass.getName();
                throw new ServiceException(DbErrorCode.DB_UNSUPPORTED_WHERE_TYPE, details);
            }
            if (entity.isEmpty()) {
                String details = "NoFieldsThatBeUpdatedWereFound, class=" + beanClass.getName();
                throw new ServiceException(DbErrorCode.DB_ENTITY_MUST_NOT_BE_EMPTY, details);
            }
            // 填充实体的修改参数(如修改人修改时间等)
            fillEntityUpdateParams(entity, fillUpdateParams);
            // 转换为DbUpdate对象
            DbUpdate ud = converter.parseMapToDbUpdate(entity);
            // 检查Where条件
            DbWhere readyWhere = checkWhere(where);
            // 填充Where条件
            entityFieldFillExecutor.fillUpdateWhereDataState(where);
            entityFieldFillExecutor.fillUpdateWhereParams(where);
            return this.doUpdate(ud, readyWhere, validStrategy, errorOnUnaffected);
        }
    }

    @Override
    public int update(T entity, DbWhere where) throws ServiceException {
        return this.update(entity, where, ValidStrategy.AUTO, true, false);
    }

    @Override
    public int update(T entity, DbWhere where, boolean fillUpdateParams, boolean errorOnUnaffected)
            throws ServiceException {
        return this.update(entity, where, ValidStrategy.AUTO, fillUpdateParams, errorOnUnaffected);
    }

    @Override
    public int update(T entity, DbWhere where, ValidStrategy validStrategy) throws ServiceException {
        return this.update(entity, where, validStrategy, true, false);
    }

    @Override
    public int update(T entity, DbWhere where, ValidStrategy validStrategy, boolean fillUpdateParams,
            boolean errorOnUnaffected) throws ServiceException {
        if (entity == null) {
            log.debug("Update set fields is empty, the update operation will be skipped.");
            return 0;
        }
        Map<String, Object> mapEntity = convertEntityAndFillUpdateParams(entity, fillUpdateParams);
        DbConditionConverter converter = jdbc.plugins().getDbConditionConverter();
        DbUpdate readyEntity = converter.parseMapToDbUpdate(mapEntity);
        if (readyEntity.isEmpty()) {
            String details = "NoFieldsThatBeUpdatedWereFound, class=" + beanClass.getName();
            throw new ServiceException(DbErrorCode.DB_ENTITY_MUST_NOT_BE_EMPTY, details);
        }

        DbWhere readyWhere = checkWhere(where);
        entityFieldFillExecutor.fillUpdateWhereDataState(readyWhere);
        entityFieldFillExecutor.fillUpdateWhereParams(readyWhere);
        return this.doUpdate(readyEntity, readyWhere, validStrategy, errorOnUnaffected);
    }

    @Override
    public int update(DbUpdate entity, DbWhere where) throws ServiceException {
        return this.update(entity, where, ValidStrategy.AUTO, true, false);
    }

    @Override
    public int update(DbUpdate entity, DbWhere where, boolean fillUpdateParams, boolean errorOnUnaffected)
            throws ServiceException {
        return this.update(entity, where, ValidStrategy.AUTO, fillUpdateParams, errorOnUnaffected);
    }

    @Override
    public int update(DbUpdate entity, DbWhere where, ValidStrategy validStrategy) throws ServiceException {
        return this.update(entity, where, validStrategy, true, false);
    }

    @Override
    public int update(DbUpdate entity, DbWhere where, ValidStrategy validStrategy, boolean fillUpdateParams,
            boolean errorOnUnaffected) throws ServiceException {
        if (entity == null || entity.isEmpty()) {
            log.debug("Update set fields is empty, the update operation will be skipped.");
            return 0;
        }
        DbWhere readyWhere = checkWhere(where);
        entityFieldFillExecutor.fillUpdateWhereDataState(readyWhere);
        entityFieldFillExecutor.fillUpdateWhereParams(readyWhere);
        // 不需要自动填充修改时的数据状态标记, 没有这样的业务场景
        // entityFieldFillExecutor.fillEntityUpdateDataState(entity);
        if (fillUpdateParams) {
            entityFieldFillExecutor.fillEntityUpdateParams(entity);
        }
        return this.doUpdate(entity, readyWhere, validStrategy, errorOnUnaffected);
    }

    protected int doUpdate(DbUpdate readyEntity, DbWhere readyWhere, ValidStrategy validStrategy,
            boolean errorOnUnaffected) throws ServiceException {
        SqlBuffer buffer = sqlHelper().buildUpdateSql(readyEntity, readyWhere, validStrategy);
        int rows;
        if (buffer.isBlank()) {
            rows = 0;
            log.debug("Update set fields is empty, the update operation will be skipped.");
        } else {
            rows = jdbc.update(buffer);
        }

        if (rows == 0 && errorOnUnaffected) {
            throw new ServiceException(DbErrorCode.DB_AFFECTED_ROWS_IS_ZERO);
        }
        return rows;
    }

    @Override
    public int updates(List<?> entities) throws ServiceException {
        return updates(entities, ValidStrategy.AUTO, true, this.defaultBatchSize);
    }

    @Override
    public int updates(List<?> entities, boolean fillUpdateParams) throws ServiceException {
        return updates(entities, ValidStrategy.AUTO, fillUpdateParams, this.defaultBatchSize);
    }

    @Override
    public int updates(List<?> entities, ValidStrategy validStrategy) throws ServiceException {
        return updates(entities, validStrategy, true, this.defaultBatchSize);
    }

    @Override
    public int updates(List<?> entities, ValidStrategy validStrategy, boolean fillUpdateParams)
            throws ServiceException {
        return updates(entities, validStrategy, fillUpdateParams, this.defaultBatchSize);
    }

    protected int updates(List<?> entities, ValidStrategy validStrategy, boolean fillUpdateParams, int batchSize)
            throws ServiceException {
        VerifyTools.requireNotBlank(entities, "entities");
        // 查找主键(批量更新必须要有主键)
        SimpleFieldColumn pk = sqlHelper().fragment().getPrimaryKey();
        if (pk == null) { // 没有找到主键字段
            String details = "UnsupportedBatchUpdate, class=" + beanClass.getName();
            throw new ServiceException(DbErrorCode.DB_PRIMARY_KEY_FIELD_IS_UNRESOLVED, details);
        }
        if (entities.size() == 1) {
            Object first = entities.get(0);
            // 将实体类转换为map, 并执行实体业务数据填充
            PkEntity pe = convertAndFillUpdateParams(first, fillUpdateParams);
            Serializable pkValue = pe.getPrimaryKey();
            if (VerifyTools.isBlank(pkValue)) { // 主键值为空
                String details = "UnsupportedBatchUpdate, class=" + beanClass.getName();
                throw new ServiceException(DbErrorCode.DB_PRIMARY_KEY_VALUE_IS_REQUIRED, details);
            }
            // 实体类转换为DbUpdate
            DbConditionConverter converter = jdbc.plugins().getDbConditionConverter();
            DbUpdate ud = converter.parseMapToDbUpdate(pe.getEntity());
            // 生成主键限制条件
            DbWhere where = new DbWhere().on(pk.getFieldName()).equals(pkValue).end();
            // 与批量处理的逻辑保持一致, 不限制数据状态
            // entityFieldFillExecutor fillUpdateWhereDataState(where);
            // entityFieldFillExecutor fillUpdateWhereParams(where);
            return this.doUpdate(ud, where, validStrategy, false);
        } else if (batchSize <= 0 || entities.size() <= batchSize) {
            return doBatchUpdates(entities, validStrategy, fillUpdateParams);
        } else { // 分批导入
            List<Object> buffer = new ArrayList<>();
            int rows = 0;
            for (int i = 1, size = entities.size(); i <= size; i++) {
                buffer.add(entities.get(i - 1));
                if (i % batchSize == 0 || i == size) {
                    rows += doBatchUpdates(buffer, validStrategy, fillUpdateParams);
                    buffer.clear();
                }
            }
            return rows;
        }
    }

    /**
     * 执行批量更新
     *
     * @param entities 实体对象列表(只能是entity或map或IdEntity列表, 其他参数将会报错)
     * @param validStrategy 校验处理策略<br>
     * <b>注意</b>: 由于@Column的length/precision/scale有默认值, 一旦启用, 则所有字段都需要覆盖设置!
     * @param fillUpdateParams 是否自动填充更新参数(修改人/修改时间等)
     * @return 受影响行数
     * @throws ServiceException 操作失败
     */
    protected int doBatchUpdates(List<?> entities, ValidStrategy validStrategy, boolean fillUpdateParams)
            throws ServiceException {
        List<PkEntity> contents = new ArrayList<>();
        for (Object item : entities) {
            // 将实体类转换为map, 并执行实体业务数据填充
            PkEntity pkud = convertAndFillUpdateParams(item, fillUpdateParams);
            contents.add(pkud);
        }
        DbVersion version = jdbc.dbVersion();
        BatchUpdateExecutor batchOperator = jdbc.plugins().getBatchUpdateExecutor(version);
        // 执行批量数据库更新
        return batchOperator.updates(contents, validStrategy, jdbc, sqlOperator);
    }

    @Override
    public int logicalDeleteById(Serializable id) throws ServiceException {
        VerifyTools.requireNotBlank(id, "id");
        return logicalDeleteById(id, true, false);
    }

    @Override
    public int logicalDeleteById(Serializable id, boolean fillUpdateParams, boolean errorOnUnaffected)
            throws ServiceException {
        VerifyTools.requireNotBlank(id, "id");
        SimpleFieldColumn pk = sqlHelper().fragment().getPrimaryKey();
        if (pk == null) { // 没有找到主键字段
            String details = "UnsupportedDeleteById, class=" + beanClass.getName();
            throw new ServiceException(DbErrorCode.DB_PRIMARY_KEY_FIELD_IS_UNRESOLVED, details);
        }

        String primaryField = pk.getFieldName();
        DbWhere where = new DbWhere().on(primaryField).equals(id).end();
        entityFieldFillExecutor.fillDeleteWhereDataState(where);
        entityFieldFillExecutor.fillDeleteWhereParams(where);
        return this.doDelete(where, false, fillUpdateParams, errorOnUnaffected);
    }

    @Override
    public int logicalDeleteByIds(Collection<? extends Serializable> ids) throws ServiceException {
        return logicalDeleteByIds(ids, true, false);
    }

    @Override
    public int logicalDeleteByIds(Collection<? extends Serializable> ids, boolean fillUpdateParams,
            boolean errorOnUnaffected) throws ServiceException {
        VerifyTools.requireNotBlank(ids, "ids");
        SimpleFieldColumn pk = sqlHelper().fragment().getPrimaryKey();
        if (pk == null) { // 没有找到主键字段
            String details = "UnsupportedDeleteById, class=" + beanClass.getName();
            throw new ServiceException(DbErrorCode.DB_PRIMARY_KEY_FIELD_IS_UNRESOLVED, details);
        }

        String primaryField = pk.getFieldName();
        DbWhere where = new DbWhere().on(primaryField).in(ids).end();
        entityFieldFillExecutor.fillDeleteWhereDataState(where);
        entityFieldFillExecutor.fillDeleteWhereParams(where);
        return this.doDelete(where, false, fillUpdateParams, errorOnUnaffected);
    }

    @Override
    public int logicalDelete(T where) throws ServiceException {
        return logicalDelete(where, true, false);
    }

    @Override
    public int logicalDelete(T where, boolean fillUpdateParams, boolean errorOnUnaffected) throws ServiceException {
        if (where == null) {
            String details = "If you want to delete all records, please use DbWhere.NONE";
            throw new ServiceException(DbErrorCode.DB_WHERE_MUST_NOT_BE_EMPTY, details);
        }
        DbConditionConverter converter = jdbc.plugins().getDbConditionConverter();
        DbWhere beanWhere = converter.convertBeanToDbWhere(where);
        DbWhere readyWhere = checkWhere(beanWhere);
        entityFieldFillExecutor.fillDeleteWhereDataState(readyWhere);
        entityFieldFillExecutor.fillDeleteWhereParams(readyWhere);
        return this.doDelete(readyWhere, false, fillUpdateParams, errorOnUnaffected);
    }

    @Override
    public int logicalDelete(DbWhere where) throws ServiceException {
        return logicalDelete(where, true, false);
    }

    @Override
    public int logicalDelete(DbWhere where, boolean fillUpdateParams, boolean errorOnUnaffected)
            throws ServiceException {
        DbWhere readyWhere = checkWhere(where);
        entityFieldFillExecutor.fillDeleteWhereDataState(readyWhere);
        entityFieldFillExecutor.fillDeleteWhereParams(readyWhere);
        return this.doDelete(readyWhere, false, fillUpdateParams, errorOnUnaffected);
    }

    @Override
    public int physicalDeleteById(Serializable id) throws ServiceException {
        return physicalDeleteById(id, false);
    }

    @Override
    public int physicalDeleteById(Serializable id, boolean errorOnUnaffected) throws ServiceException {
        VerifyTools.requireNotBlank(id, "id");
        SimpleFieldColumn pk = sqlHelper().fragment().getPrimaryKey();
        if (pk == null) { // 没有找到主键字段
            String details = "UnsupportedDeleteById, class=" + beanClass.getName();
            throw new ServiceException(DbErrorCode.DB_PRIMARY_KEY_FIELD_IS_UNRESOLVED, details);
        }

        String primaryField = pk.getFieldName();
        DbWhere where = new DbWhere().on(primaryField).equals(id).end();
        return this.doDelete(where, true, false, errorOnUnaffected);
    }

    @Override
    public int physicalDeleteByIds(Collection<? extends Serializable> ids) throws ServiceException {
        return physicalDeleteByIds(ids, false);
    }

    @Override
    public int physicalDeleteByIds(Collection<? extends Serializable> ids, boolean errorOnUnaffected)
            throws ServiceException {
        VerifyTools.requireNotBlank(ids, "ids");
        SimpleFieldColumn pk = sqlHelper().fragment().getPrimaryKey();
        if (pk == null) { // 没有找到主键字段
            String details = "UnsupportedDeleteById, class=" + beanClass.getName();
            throw new ServiceException(DbErrorCode.DB_PRIMARY_KEY_FIELD_IS_UNRESOLVED, details);
        }

        String primaryField = pk.getFieldName();
        DbWhere where = new DbWhere().on(primaryField).in(ids).end();
        return this.doDelete(where, true, false, errorOnUnaffected);
    }

    @Override
    public int physicalDelete(T where) throws ServiceException {
        return physicalDelete(where, false);
    }

    @Override
    public int physicalDelete(T where, boolean errorOnUnaffected) throws ServiceException {
        if (where == null) {
            String details = "If you want to delete all records, please use DbWhere.NONE";
            throw new ServiceException(DbErrorCode.DB_WHERE_MUST_NOT_BE_EMPTY, details);
        }
        DbConditionConverter converter = jdbc.plugins().getDbConditionConverter();
        DbWhere beanWhere = converter.convertBeanToDbWhere(where);
        DbWhere readyWhere = checkWhere(beanWhere);
        return this.doDelete(readyWhere, true, false, errorOnUnaffected);
    }

    @Override
    public int physicalDelete(DbWhere where) throws ServiceException {
        return this.doDelete(where, true, false, false);
    }

    @Override
    public int physicalDelete(DbWhere where, boolean errorOnUnaffected) throws ServiceException {
        return this.doDelete(where, true, false, errorOnUnaffected);
    }

    protected int doDelete(DbWhere readyWhere, boolean physical, boolean fillUpdateParams, boolean errorOnUnaffected)
            throws ServiceException {
        int rows;
        if (physical) { // 物理删除
            SqlBuffer buffer = sqlHelper().buildDeleteSql(readyWhere);
            rows = jdbc.delete(buffer);
        } else { // 逻辑删除
            if (entityFieldFillExecutor.supportedTableLogicalDelete()) { // 支持逻辑删除
                DbUpdate ud = new DbUpdate();
                entityFieldFillExecutor.fillLogicalDeleteDataState(ud);
                if (fillUpdateParams) {
                    entityFieldFillExecutor.fillLogicalDeleteParams(ud);
                }
                SqlBuffer buffer = sqlHelper().buildUpdateSql(ud, readyWhere, ValidStrategy.AUTO);
                if (buffer.isBlank()) {
                    rows = 0;
                    log.debug("Update set fields is empty, the logical delete operation will be skipped.");
                } else {
                    rows = jdbc.update(buffer);
                }
            } else { // 不支持逻辑删除
                String details = "UnsupportedLogicDelete, class=" + beanClass.getName();
                throw new ServiceException(DbErrorCode.DB_UNSUPPORTED_LOGICAL_DELETE, details);
            }
        }

        if (rows == 0 && errorOnUnaffected) {
            throw new ServiceException(DbErrorCode.DB_AFFECTED_ROWS_IS_ZERO);
        }
        return rows;
    }

    /**
     * 执行实体业务数据转换及创建参数填充<br>
     * 作为以下两个方法的入口, 参数只支持map和T两种:<br>
     * fillEntityCreateParams(Map, boolean)/convertEntityAndFillCreateParams(T, boolean)<br>
     *
     * @param object 实体对象, 只支持map和T两种
     * @param fillCreateParams 是否自动填充创建参数
     * @return 实体类转换后的map和自动填充的主键ID
     */
    protected PkEntity convertAndFillCreateParams(Object object, boolean fillCreateParams) {
        if (object == null) {
            String details = "CanNotExecuteCreate, class=" + beanClass.getName();
            throw new ServiceException(DbErrorCode.DB_ENTITY_MUST_NOT_BE_EMPTY, details);
        }
        if (object instanceof PkEntity) {
            PkEntity pe = (PkEntity) object;
            Map<String, Object> entity = pe.getEntity();
            SimpleFieldColumn pk = sqlHelper().fragment().getPrimaryKey();
            // 如果PkEntity里面的id不为空, 设置到entity中
            if (pk != null && VerifyTools.isNotBlank(pe.getPrimaryKey())) {
                entity.put(pk.getFieldName(), pe.getPrimaryKey());
            }
            if (entity.isEmpty()) {
                String details = "NoFieldsThatBeInsertedWereFound, class=" + beanClass.getName();
                throw new ServiceException(DbErrorCode.DB_ENTITY_MUST_NOT_BE_EMPTY, details);
            }
            // 填充主键/数据状态/创建人/创建时间等信息
            fillEntityCreateParams(entity, fillCreateParams);
            return pe;
        } else if (object instanceof Map) {
            @SuppressWarnings("unchecked")
            Map<String, Object> entity = (Map<String, Object>) object;
            if (entity.isEmpty()) {
                String details = "NoFieldsThatBeInsertedWereFound, class=" + beanClass.getName();
                throw new ServiceException(DbErrorCode.DB_ENTITY_MUST_NOT_BE_EMPTY, details);
            }
            String id = fillEntityCreateParams(entity, fillCreateParams);
            return new PkEntity(id, entity);
        } else if (beanClass.isAssignableFrom(object.getClass())) {
            @SuppressWarnings("unchecked")
            T entity = (T) object;
            return convertEntityAndFillCreateParams(entity, fillCreateParams);
        } else {
            String details = "CanNotExecuteCreate, class=" + beanClass.getName();
            throw new ServiceException(DbErrorCode.DB_UNSUPPORTED_ENTITY_TYPE, details);
        }
    }

    /**
     * 执行实体业务数据创建参数填充<br>
     * 1. 查找主键ID, 如果有主键字段且字段值为空, 就自动生成ID<br>
     * 2. 填充创建参数中的数据状态<br>
     * 3. 如果fillCreateParams=true, 则填充其他创建参数
     *
     * @param entity 实体对象
     * @param fillCreateParams 是否自动填充创建参数
     * @return 填充或获取的主键ID
     */
    protected String fillEntityCreateParams(Map<String, Object> entity, boolean fillCreateParams) {
        String tableName = sqlHelper().fragment().getTableName();
        // 查找主键
        String id;
        SimpleFieldColumn pk = sqlHelper().fragment().getPrimaryKey();
        if (pk == null) {
            id = null;
        } else if (VerifyTools.isNotBlank(entity.get(pk.getFieldName()))) {
            Object pkValue = SqlTools.unwrapDbVariable(entity.get(pk.getFieldName()));
            id = pkValue.toString();
        } else {
            // 生成主键
            entity.put(pk.getFieldName(), id = entityFieldFillExecutor.generatePrimaryKeyCode(tableName));
        }
        entityFieldFillExecutor.fillEntityCreateDataState(entity);
        if (fillCreateParams) {
            entityFieldFillExecutor.fillEntityCreateParams(entity);
        }
        return id;
    }

    /**
     * 执行实体业务数据转换及创建参数填充<br>
     * 这里存在一个问题, 执行fillEntityCreateParams之后, 入参entity中的字段得不到更新<br>
     * 因此, 执行fillEntityCreateParams之前先记录下所有字段值原值<br>
     * 执行完fillEntityCreateParams之后比对字段差异, 将差异部分设置回入参entity中<br>
     * 比对差异是为了提升性能, 因为对entity操作需要用到反射, 而比对差异只是对map操作, 快很多<br>
     * 例如一个类有20个字段, fillEntityCreateParams只修改了2个, 比对差异可以避免对其他18个字段的反射操作<br>
     *
     * @param entity 实体对象
     * @param fillCreateParams 是否自动填充创建参数
     * @return 实体类转换后的map和自动填充的主键ID
     */
    protected PkEntity convertEntityAndFillCreateParams(T entity, boolean fillCreateParams) {
        // 将对象转换为map
        DbConditionConverter conditionConverter = jdbc.plugins().getDbConditionConverter();
        Map<String, Object> readyEntity = conditionConverter.convertBeanToInsertMap(entity);
        if (readyEntity.isEmpty()) {
            String details = "NoFieldsThatBeInsertedWereFound, class=" + beanClass.getName();
            throw new ServiceException(DbErrorCode.DB_ENTITY_MUST_NOT_BE_EMPTY, details);
        }
        // 记录下所有字段值原值, 用于比较差异
        Map<String, Object> original = new HashMap<>(readyEntity);
        // 填充主键/数据状态/创建人/创建时间等信息
        String id = fillEntityCreateParams(readyEntity, fillCreateParams);
        // 比对修改后的字段值与原值的差异, 复制到原对象
        Map<String, Object> diff = copmareMapDifference(original, readyEntity);
        MapToBeanConverter mapToBeanConverter = jdbc.plugins().getMapToBeanConverter();
        mapToBeanConverter.fillTo(diff, entity);
        return new PkEntity(id, readyEntity);
    }

    /**
     * 执行实体业务数据转换及更新参数填充
     *
     * @param object 实体对象, 只支持map/T/PkEntity, 其他类型将会报错<br>
     * 如果object是map, map中不能有where, 如果有,调这个方法之前要移除, 否则将会报错
     * @param fillUpdateParams 是否自动填充更新参数
     * @return 转换后的update和where
     */
    protected PkEntity convertAndFillUpdateParams(Object object, boolean fillUpdateParams) {
        if (object == null) {
            String details = "CanNotExecuteUpdate, EntityIsNull, class=" + beanClass.getName();
            throw new ServiceException(DbErrorCode.DB_ENTITY_MUST_NOT_BE_EMPTY, details);
        }
        // 查找主键
        SimpleFieldColumn pk = sqlHelper().fragment().getPrimaryKey();
        if (pk == null) { // 没有找到主键字段
            String details = "UnsupportedBatchUpdate, class=" + beanClass.getName();
            throw new ServiceException(DbErrorCode.DB_PRIMARY_KEY_FIELD_IS_UNRESOLVED, details);
        }
        if (object instanceof PkEntity) {
            PkEntity pe = (PkEntity) object;
            Serializable pkValue = pe.getPrimaryKey();
            // 主键值不能为空
            if (VerifyTools.isBlank(pkValue)) { // 主键值为空
                String details = "CanNotExecuteUpdateById, class=" + beanClass.getName();
                throw new ServiceException(DbErrorCode.DB_PRIMARY_KEY_VALUE_IS_REQUIRED, details);
            }
            Map<String, Object> entity = pe.getEntity();
            // 检查UpdateEntity
            checkUpdateEntity(entity);
            // 填充实体的修改参数(如修改人修改时间等)
            fillEntityUpdateParams(entity, fillUpdateParams);
            return pe;
        } else if (object instanceof Map) {
            @SuppressWarnings("unchecked")
            Map<String, Object> entity = (Map<String, Object>) object;
            // 检查UpdateEntity
            checkUpdateEntity(entity);
            Object pkValue = entity.get(pk.getFieldName());
            // 主键值不能为空
            if (VerifyTools.isBlank(pkValue)) { // 主键值为空
                String details = "CanNotExecuteUpdateById, class=" + beanClass.getName();
                throw new ServiceException(DbErrorCode.DB_PRIMARY_KEY_VALUE_IS_REQUIRED, details);
            }
            // 填充实体的修改参数(如修改人修改时间等)
            fillEntityUpdateParams(entity, fillUpdateParams);
            return new PkEntity(SqlTools.unwrapDbVariable(pkValue).toString(), entity);
        } else if (beanClass.isAssignableFrom(object.getClass())) {
            @SuppressWarnings("unchecked")
            T entity = (T) object;
            Map<String, Object> map = convertEntityAndFillUpdateParams(entity, fillUpdateParams);
            Object pkValue = map.get(pk.getFieldName());
            // 主键值不能为空
            if (VerifyTools.isBlank(pkValue)) { // 主键值为空
                String details = "CanNotExecuteUpdateById, class=" + beanClass.getName();
                throw new ServiceException(DbErrorCode.DB_PRIMARY_KEY_VALUE_IS_REQUIRED, details);
            }
            return new PkEntity(pkValue.toString(), map);
        } else {
            String details = "CanNotExecuteUpdate, class=" + beanClass.getName();
            throw new ServiceException(DbErrorCode.DB_UNSUPPORTED_ENTITY_TYPE, details);
        }
    }

    private void checkUpdateEntity(Map<String, Object> entity) {
        if (entity == null || entity.isEmpty()) {
            String details = "NoFieldsThatBeUpdatedWereFound, class=" + beanClass.getName();
            throw new ServiceException(DbErrorCode.DB_ENTITY_MUST_NOT_BE_EMPTY, details);
        }
        if (entity.containsKey("where")) {
            // entity里面不能有where, 如果有,调这个方法之前要移除, 否则将会报错
            // 因为批量更新的语法不支持每个ID带有不同的where条件
            String details = "Unsupported entity.where";
            throw new ServiceException(ResultCode.PARAMETER_VALUE_ERROR, details);
        }
    }

    /**
     * 执行实体业务数据更新参数填充
     *
     * @param entity 实体对象
     * @param fillUpdateParams 是否自动填充创建参数
     */
    protected void fillEntityUpdateParams(Map<String, Object> entity, boolean fillUpdateParams) {
        // 不需要自动填充修改时的数据状态标记, 没有这样的业务场景
        // entityFieldFillExecutor.fillEntityUpdateDataState(entity);
        if (fillUpdateParams) { // 填充单表修改参数(如修改人修改时间等)
            entityFieldFillExecutor.fillEntityUpdateParams(entity);
        }
    }

    /**
     * 执行实体业务数据更新参数填充
     *
     * @param ud 待更新的内容
     * @param fillUpdateParams 是否自动填充创建参数
     */
    protected void fillEntityUpdateParams(DbUpdate ud, boolean fillUpdateParams) {
        // 不需要自动填充修改时的数据状态标记, 没有这样的业务场景
        // entityFieldFillExecutor.fillEntityUpdateDataState(ud);
        if (fillUpdateParams) { // 填充单表修改参数(如修改人修改时间等)
            entityFieldFillExecutor.fillEntityUpdateParams(ud);
        }
    }

    /**
     * 执行实体业务数据创建参数填充<br>
     * 这里存在一个问题, 执行fillEntityUpdateParams之后, 入参entity中的字段得不到更新<br>
     * 因此, 执行fillEntityUpdateParams之前先记录下所有字段值原值<br>
     * 执行完fillEntityUpdateParams之后比对字段差异, 将差异部分设置回入参entity中<br>
     * 比对差异是为了提升性能, 因为对entity操作需要用到反射, 而比对差异只是对map操作, 快很多<br>
     * 例如一个类有20个字段, fillEntityUpdateParams只修改了2个, 比对差异可以避免对其他18个字段的反射操作<br>
     *
     * @param entity 实体对象
     * @param fillUpdateParams 是否自动填充更新参数
     * @return 实体类转换后的map
     */
    protected Map<String, Object> convertEntityAndFillUpdateParams(T entity, boolean fillUpdateParams) {
        // 将对象转换为map
        DbConditionConverter conditionConverter = jdbc.plugins().getDbConditionConverter();
        Map<String, Object> readyEntity = conditionConverter.convertBeanToUpdateMap(entity);
        if (readyEntity.isEmpty()) {
            String details = "NoFieldsThatBeUpdatedWereFound, class=" + beanClass.getName();
            throw new ServiceException(DbErrorCode.DB_ENTITY_MUST_NOT_BE_EMPTY, details);
        }
        // 记录下所有字段值原值, 用于比较差异
        Map<String, Object> original = new HashMap<>(readyEntity);
        // 填充主键/数据状态/创建人/创建时间等信息
        fillEntityUpdateParams(readyEntity, fillUpdateParams);
        // 比对修改后的字段值与原值的差异, 复制到原对象
        Map<String, Object> diff = copmareMapDifference(original, readyEntity);
        MapToBeanConverter mapToBeanConverter = jdbc.plugins().getMapToBeanConverter();
        mapToBeanConverter.fillTo(diff, entity);
        return readyEntity;
    }

    /** 获取当前实例的Bean类型 **/
    @Override
    public Class<T> getBeanClass() {
        return beanClass;
    }

    /** 批量执行时的大小限制(0为无限制) **/
    protected int getDefaultBatchSize() {
        return defaultBatchSize;
    }

    /** 批量执行时的大小限制(0为无限制) **/
    protected void setDefaultBatchSize(int batchSize) {
        this.defaultBatchSize = batchSize;
    }

    private static class CrudSqlOperator implements SqlOperator<CrudSqlHelper> {

        private final SqlBoot sqlBoot;
        private final CrudSqlHelper sqlHelper;

        public CrudSqlOperator(Class<?> beanClass, SqlBoot sqlBoot) {
            this.sqlBoot = sqlBoot;
            this.sqlHelper = sqlBoot.sqlHelper(beanClass);
        }

        @Override
        public SqlBuffer newSqlBuffer() {
            return sqlBoot.newSqlBuffer();
        }

        @Override
        public SqlBuilder newSqlBuilder() {
            return sqlBoot.newSqlBuilder();
        }

        @Override
        public ParseTools parseTools() {
            return sqlBoot.parseTools();
        }

        @Override
        public CommonSqlTools sqlTools() {
            return sqlBoot.sqlTools();
        }

        @Override
        public CrudSqlHelper sqlHelper() {
            return sqlHelper;
        }

        @Override
        public SqlFragmentContainer sqlContainer() {
            return sqlBoot.sqlContainer();
        }

        @Override
        public SqlDialect sqlDialect() {
            return sqlBoot.sqlDialect();
        }

        @Override
        public DbPluginHelper plugins() {
            return sqlBoot.plugins();
        }
    }
}
